﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharePoint2007Migration.Domain.Collections;
using Microsoft.SharePoint;
using System.Collections.Specialized;
using System.Xml;
using System.IO;
using Microsoft.SharePoint.WebPartPages;

namespace SharePoint2007Migration.Domain
{
    public class MissingWebPartReport : BaseReport
    {


        WebPartDefinitionCollection _webPartDefinitionInCurrentContentDb;

        public MissingWebPartReport(MissingWebPartIssueCollection wp)
            : base(wp.ToIssueCollection())
        {

            this.MissingWebPartIssueCollection = wp;
        }

        public MissingWebPartIssueCollection MissingWebPartIssueCollection { get; private set; }


        public WebPartDefinitionCollection WebPartDefinitionsInCurrentContentDb 
        {
            get 
            {
                if (_webPartDefinitionInCurrentContentDb == null)
                        _webPartDefinitionInCurrentContentDb = GetAllWebPartsDefinitionsInCurrentContentDb();
                return _webPartDefinitionInCurrentContentDb;
            }
        }

        public WebPartDefinitionCollection GetMissingWebPartsDefinitions()
        {

            #region help links

            //  http://social.technet.microsoft.com/Forums/en-US/sharepoint2010setup/thread/6dd8f218-2eef-4c6f-a17d-ab34e28a5879
            //  http://social.msdn.microsoft.com/Forums/en-US/sharepointdevelopment/thread/a0fc0978-0d55-463a-b7ab-72c00aee76a3

            #endregion

            LogHelper.TraceDebugImportant("Analyzing WebPart's started");

            WebPartDefinitionCollection result = new WebPartDefinitionCollection();
    
            foreach (MissingWebPartIssue missingWebPartIssue in this.MissingWebPartIssueCollection)
            {
                try
                {
                    WebPartDefintion wp = this.WebPartDefinitionsInCurrentContentDb[missingWebPartIssue.WebPartId];
                    result.Add(wp);
                }
                catch (KeyNotFoundException)
                {
                    LogHelper.TraceDebugImportant("#### Unable to locate the following WebPart Issue into current content db");
                    LogHelper.TraceDebug(String.Concat("-> WebPart id ", missingWebPartIssue.WebPartId));
                }
                catch (Exception ex)
                {
                    LogHelper.TraceError(ex);
                }
            }
            LogHelper.TraceDebugImportant("Analyzing WebPart's ended");
            return result;

        }

        public override string CreateReport()
        {
            StringBuilder sb = new StringBuilder();

            sb.AppendLine(CreateReportBanner("WebParts Report"));
            sb.AppendLine(GetResolvedWebPartsInformations());
            return sb.ToString();
        }


        // private methods

        private WebPartDefinitionCollection GetAllWebPartsDefinitionsInCurrentContentDb()
        {
            LogHelper.TraceDebugImportant("Search for all web parts in current content db has starded");
            LogHelper.TraceDebug("WebParts will be loaded from the following sitecollections:");

            foreach (var item in this.SiteCollectionUrls)
                LogHelper.TraceDebug(string.Concat("   ->", item));
            
            WebPartDefinitionCollection result = new WebPartDefinitionCollection();
            foreach (var siteCollectionUrl in this.SiteCollectionUrls)
            {
                using (SPSite site = new SPSite (siteCollectionUrl))
                {
                    LogHelper.TraceDebug(String.Concat(site.Url, " spsite have been opened successfully" ));
                    using (SPWeb web = site.OpenWeb())
                    {
                        GetWebPartDefinitionsFromSpWeb(result, web);
                    }
                }
            }
            LogHelper.TraceDebugImportant("[Ok] Search for all web parts in current content db has terminated ");
            return result;
        }

        private void GetWebPartDefinitionsFromSpWeb(WebPartDefinitionCollection result, SPWeb web)
        {
            LogHelper.TraceDebug(String.Concat("Retriving WebParts from spweb: ", web.Url));
            SPList webPartGallery = web.GetCatalog(SPListTemplateType.WebPartCatalog);
            LogHelper.TraceDebug(String.Concat("Found: ", webPartGallery.ItemCount, " webparts into Wp Catalog " ));

            if (webPartGallery != null)
                foreach (SPListItem item in webPartGallery.Items)
                {
                    try
                    {
                        SPFile webpartFile = item.File;
                        LogHelper.TraceDebug(String.Concat("Retriving ",  item.DisplayName, " web part definition ", web.Url));
                        if (webpartFile != null)
                        {
                            using (System.IO.StreamReader reader = new System.IO.StreamReader(webpartFile.OpenBinaryStream()))
                            {
                                string wpXml = reader.ReadToEnd();
                                XmlDocument xml = new XmlDocument();
                                xml.LoadXml(wpXml);
                                WebPartDefintion wp = new WebPartDefintion(item.DisplayName , xml);
                                result.Add(wp);
                                LogHelper.TraceDebug(String.Concat("[OK] ", item.DisplayName, " 's WebPart definition have been examinated succesfully"));
                            }
                        }
                        else LogHelper.TraceDebug(String.Concat("Item ", item.DisplayName, " has no WebPArt definition"));
                    }
                    catch (FileNotFoundException ex)
                    {
                        // do nothing...
                        // wp are loaded from filesystem 
                        // C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES
                        // some features leaves .webparts files into gallery.
                        LogHelper.TraceError(ex);
                    }
                    catch (Exception ex)
                    {
                        LogHelper.TraceError(ex);
                    }
                }
        }


        private string GetResolvedWebPartsInformations()
        {

            StringBuilder result = new StringBuilder();

            WebPartDefinitionCollection missingWebParts = GetMissingWebPartsDefinitions();
            MissingWebPartIssueCollection webPartIssuesNotAnalized = GetMissingWebPartsNotResolved(missingWebParts);

            result.AppendLine(CreateIssueCountInformations(this.MissingWebPartIssueCollection.Count, missingWebParts.Count,
               this.WebPartDefinitionsInCurrentContentDb.Count, "WebParts"));

            foreach (KeyValuePair<Guid, WebPartDefintion> kvp in missingWebParts)
            {
                WebPartDefintion wpDefinition = kvp.Value;
                CreateWebPartBanner(result, wpDefinition.Name);
                result.AppendLine("WebPart Details: " + wpDefinition.Name);
                result.AppendLine(wpDefinition.ToString());
                result.AppendLine("This wep part can be located in the following pages:");
                foreach (var url in wpDefinition.GetPageUrlWhereWebPartIsInstalled(this.ContentDbConnectionString))
                {
                    result.AppendLine(url);
                }
                result.AppendLine("______________________________________________________________");
            }


            if (webPartIssuesNotAnalized.Count != 0)
            {
                result.AppendLine("############################################################################");
                result.AppendLine("############### the following web parts could not be analized ################");
                result.AppendLine("############################################################################");
                foreach (var wp in webPartIssuesNotAnalized)
                {
                    CreateWebPartBanner(result, wp.WebPartId.ToString());
                    result.AppendLine(" This web part can be located in the follwoing urls:");
                    foreach (var item in wp.GetPageUrlWhereWebPartIsInstalled(this.ContentDbConnectionString))
                    {
                        result.AppendLine(item);
                    }
                    result.AppendLine();
                }
            }
            

            

            return result.ToString();
        }

        private static void CreateWebPartBanner(StringBuilder result, string title)
        {
            result.AppendLine("==============================================================");
            result.AppendLine("[WebPart : " + title + "]");
            result.AppendLine("==============================================================");
        }

        private MissingWebPartIssueCollection GetMissingWebPartsNotResolved(WebPartDefinitionCollection missingWebParts)
        {
            MissingWebPartIssueCollection result = new MissingWebPartIssueCollection();
            foreach (var WebPArtIssues in this.MissingWebPartIssueCollection)
            {
                try
                {
                    WebPartDefintion wp = this.WebPartDefinitionsInCurrentContentDb[WebPArtIssues.WebPartId];
                }
                catch (KeyNotFoundException)
                {
                    result.Add(WebPArtIssues);
                }
            }
            return result;
        }
    }
}
